#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using DBService.ExternalContent;
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using UnityEngine;
using UnityEngine.AddressableAssets;

namespace OA
{
    public partial class CallDlcAsset : EditorWindow
    {

        void BuildPrograms(List<DLCAssetInfo> _dlcAssets, Dictionary<string, bool> _dlcSelection, bool isOvver = false)
        {
            var selectedDLCs = _dlcAssets.Where(d => _dlcSelection[d.DLCName]).ToList();
            if (selectedDLCs.Count == 0)
            {
                EditorUtility.DisplayDialog("提示", "请至少选择一个DLC", "确定");
                return;
            }

            foreach (var dlc in selectedDLCs)
            {
                try
                {
                    string dlcDir = Path.GetDirectoryName(dlc.AssetPath);
                    string parentDir = Directory.GetParent(dlcDir).FullName;
                    string programDir = Path.Combine(parentDir, $"{dlc.DLCName}_Program~");
                    string dllDir = Path.Combine(programDir, "dlls");
                    // 如果不需要重构，删除除 sln、csproj、dll/ 以外的文件和文件夹
                    if (!isOvver && Directory.Exists(programDir))
                    {
                        CleanProgramDirectory(programDir);
                    }
                    else
                    {
                        // 如果需要重构，删除除 dlls 文件夹外的所有文件
                        if (Directory.Exists(programDir))
                            CleanProgramDirectory(programDir);
                    }

                    Directory.CreateDirectory(programDir);
                    Directory.CreateDirectory(dllDir);
                    AssetDatabase.Refresh();
                    // 1️⃣ 收集所有脚本
                    var scriptFiles = Directory.GetFiles(dlcDir, "*.cs", SearchOption.AllDirectories).Where(f => f.Contains("Scripts") ||
                     f.Contains("ScriptsMotion") || f.Contains("_GateWay")).ToList();

                    if (scriptFiles.Count == 0)
                    {
                        LogWarning($"DLC {dlc.DLCName} 未找到 Scripts 或 ScriptsMotion 文件夹。");
                        continue;
                    }

                    // 2️⃣ 复制脚本
                    foreach (var file in scriptFiles)
                    {
                        string relative = Path.GetRelativePath(dlcDir, file);
                        string dest = Path.Combine(programDir, relative);
                        Directory.CreateDirectory(Path.GetDirectoryName(dest));
                        File.Copy(file, dest, true);
                    }

                    string scriptAssembliesDir = Path.Combine(Application.dataPath, "..", "Library", "ScriptAssemblies");

                    string[] dllNames = new string[] { "UnityEditor", "UnityEngine", "appframework", "BasicFramework", "cvdcommand", "databaseservice", "fairygui", "motion" };

                    GenerateCSProjAndSLN(dlc, programDir, scriptAssembliesDir, dllNames, isOvver);

                    //  CompileDlcWithCommandLine(programDir, dlc.DLCName);

                    Log($"✅ 同步完成: {dlc.DLCName}_Program~");
                }
                catch (Exception ex)
                {
                    LogError($"❌ 同步失败 {dlc.DLCName} 失败: {ex.Message}");
                }
            }

            AssetDatabase.Refresh();
        }

        private void GenerateCSProjAndSLN(DLCAssetInfo dlc, string programDir, string scriptAssembliesDir, string[] dllNames, bool isOvver)
        {
            string csprojPath = Path.Combine(programDir, $"{dlc.DLCName}.csproj");
            string slnPath = Path.Combine(programDir, $"{dlc.DLCName}.sln");

            var haveCsproj = File.Exists(csprojPath);
            var haveSln = File.Exists(slnPath);
            if (!isOvver && haveCsproj && haveSln)
                return;


            if (haveCsproj)
                File.Delete(csprojPath);
            if (haveSln)
                File.Delete(slnPath);


            // 构建 DLL 引用部分
            string referencesItemGroup = "";

            if (Directory.Exists(scriptAssembliesDir))
            {
                referencesItemGroup = "  <ItemGroup>\n";

                // 计算从 csproj 文件到 Library/ScriptAssemblies 的相对路径
                string relativePathToScriptAssemblies = GetRelativePath(programDir, scriptAssembliesDir);

                foreach (string dllName in dllNames)
                {
                    string dllPath = Path.Combine(scriptAssembliesDir, dllName + ".dll");
                    if (File.Exists(dllPath))
                    {
                        string assemblyName = Path.GetFileNameWithoutExtension(dllName);
                        referencesItemGroup += $"    <Reference Include=\"{assemblyName}\">\n";
                        referencesItemGroup += $"      <HintPath>{relativePathToScriptAssemblies}\\{dllName}</HintPath>\n";
                        referencesItemGroup += "    </Reference>\n";
                    }
                    else
                    {
                        LogWarning($"⚠️ 未找到 DLL 文件: {dllPath}");
                    }
                }

                referencesItemGroup += "  </ItemGroup>\n";
            }
            else
            {
                LogWarning($"⚠️ 未找到 Library/ScriptAssemblies 目录: {scriptAssembliesDir}");
            }


            var csproj = $@"
                <Project Sdk=""Microsoft.NET.Sdk"">
                  <PropertyGroup>
                    <TargetFramework>netstandard2.1</TargetFramework>
                    <OutputType>Library</OutputType>
                    <AssemblyName>{dlc.DLCName}</AssemblyName>
                    <RootNamespace>{dlc.DLCName}</RootNamespace>
                  </PropertyGroup>
                {referencesItemGroup}                      
                </Project>";

            File.WriteAllText(csprojPath, csproj);

            // 生成更完整的解决方案文件
            string projectGuid = Guid.NewGuid().ToString().ToUpper();
            var slnContent = $"Microsoft Visual Studio Solution File, Format Version 12.00\n" +
                            $"# Visual Studio Version 17\n" +
                            $"VisualStudioVersion = 17.0.31903.59\n" +
                            $"MinimumVisualStudioVersion = 10.0.40219.1\n" +
                            $"Project(\"{{9A19103F-16F7-4668-BE54-9A1E7A4F7556}}\") = \"{dlc.DLCName}\", \"{dlc.DLCName}.csproj\", \"{{{projectGuid}}}\"\n" +
                            $"EndProject\n" +
                            $"Global\n" +
                            $"\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n" +
                            $"\t\tDebug|Any CPU = Debug|Any CPU\n" +
                            $"\t\tRelease|Any CPU = Release|Any CPU\n" +
                            $"\tEndGlobalSection\n" +
                            $"\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n" +
                            $"\t\t{{{projectGuid}}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n" +
                            $"\t\t{{{projectGuid}}}.Debug|Any CPU.Build.0 = Debug|Any CPU\n" +
                            $"\t\t{{{projectGuid}}}.Release|Any CPU.ActiveCfg = Release|Any CPU\n" +
                            $"\t\t{{{projectGuid}}}.Release|Any CPU.Build.0 = Release|Any CPU\n" +
                            $"\tEndGlobalSection\n" +
                            $"\tGlobalSection(SolutionProperties) = preSolution\n" +
                            $"\t\tHideSolutionNode = FALSE\n" +
                            $"\tEndGlobalSection\n" +
                            $"EndGlobal\n";
            File.WriteAllText(slnPath, slnContent);
        }

        private void CleanProgramDirectory(string programDir)
        {
            try
            {
                if (!Directory.Exists(programDir))
                    return;

                // 获取目录中的所有文件和文件夹
                var allItems = Directory.GetFileSystemEntries(programDir, "*", SearchOption.AllDirectories);

                StringBuilder builder = new StringBuilder();
                foreach (var item in allItems)
                {
                    // 检查是否为需要保留的文件或文件夹
                    if (ShouldKeepItem(item, programDir))
                        continue;

                    // 删除不需要保留的文件或文件夹
                    if (File.Exists(item))
                    {
                        File.Delete(item);
                        builder.AppendLine($"🗑️ 删除文件: {Path.GetRelativePath(programDir, item)}");
                    }
                    else if (Directory.Exists(item))
                    {
                        Directory.Delete(item, true);
                        builder.AppendLine($"🗑️ 删除文件夹: {Path.GetRelativePath(programDir, item)}");
                    }
                }
                builder.AppendLine($"✅ 清理完成: {programDir}");
                Log(builder.ToString());
            }
            catch (Exception ex)
            {
                LogError($"❌ 清理目录失败: {ex.Message}");
            }
        }

        private bool ShouldKeepItem(string itemPath, string programDir)
        {
            string relativePath = Path.GetRelativePath(programDir, itemPath);

            // 保留 sln 文件
            if (relativePath.EndsWith(".sln", StringComparison.OrdinalIgnoreCase))
                return true;

            // 保留 csproj 文件
            if (relativePath.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase))
                return true;

            // 保留 dlls 文件夹及其内容
            if (relativePath.StartsWith("dlls", StringComparison.OrdinalIgnoreCase) ||
                relativePath.StartsWith("dlls\\", StringComparison.OrdinalIgnoreCase) ||
                relativePath.StartsWith("dlls/", StringComparison.OrdinalIgnoreCase))
                return true;

            // 其他文件和文件夹需要删除
            return false;
        }

        private string GetRelativePath(string fromPath, string toPath)
        {
            try
            {
                Uri fromUri = new Uri(fromPath + Path.DirectorySeparatorChar);
                Uri toUri = new Uri(toPath + Path.DirectorySeparatorChar);
                Uri relativeUri = fromUri.MakeRelativeUri(toUri);
                string relativePath = Uri.UnescapeDataString(relativeUri.ToString());

                // 将 URI 路径分隔符转换为系统路径分隔符
                relativePath = relativePath.Replace('/', Path.DirectorySeparatorChar);

                return relativePath;
            }
            catch (Exception ex)
            {
                LogError($"❌ 计算相对路径失败: {ex.Message}");
                // 如果计算失败，返回默认的相对路径
                return "..\\..\\Library\\ScriptAssemblies";
            }
        }

        void CompileDlcWithCommandLine(List<DLCAssetInfo> _dlcAssets, Dictionary<string, bool> _dlcSelection)
        {
            var selectedDLCs = _dlcAssets.Where(d => _dlcSelection[d.DLCName]).ToList();
            if (selectedDLCs.Count == 0)
            {
                EditorUtility.DisplayDialog("提示", "请至少选择一个DLC", "确定");
                return;
            }
            foreach (var dlcInfo in selectedDLCs)
            {
                string dlcDir = Path.GetDirectoryName(dlcInfo.AssetPath);
                string parentDir = Directory.GetParent(dlcDir).FullName;
                string programDir = Path.Combine(parentDir, $"{dlcInfo.DLCName}_Program~");
                BuildDll(programDir, dlcInfo.DLCName);

                FileInfo dllFile = null;
                FileInfo pdbFile = null;
                try
                {
                    var dir = new DirectoryInfo(programDir);
                    var releaseDir = dir.GetDirectories("bin")[0].GetDirectories("Release")[0];
                    director(releaseDir, $"{dlcInfo.DLCName}.dll", $"{dlcInfo.DLCName}.pdb", out dllFile, out pdbFile);
                }
                catch (Exception e) when (e is NullReferenceException || e is IndexOutOfRangeException)
                {
                    LogError("编译错误!，无法定位bin/Release文件夹");
                }

                string introPath = Path.Combine(dlcDir, $"{dlcInfo.DLCName}_Intro.prefab");

                var introPrefab = PrefabUtility.LoadPrefabContents(introPath);
                var intro = introPrefab.GetComponent<Intro>();

                intro.mainClassName = $"{dlcInfo.DLCName}.{dlcInfo.DLCName}_GateWay";

                if (dllFile == null || pdbFile == null)
                {
                    //把Intro的信息删掉
                    intro.dllReferences = null;
                    intro.pdbReferences = null;
                    PrefabUtility.SaveAsPrefabAsset(introPrefab, introPath);
                    AssetDatabase.Refresh();

                    LogError("编译错误！未生成DLL，已删除工程中dll文件，已清理Intro预制体对dll的引用");
                }
                else
                {
                    //把Dll和pdb拷回来，然后加到Addressable里边
                    var dllFileName = $"{dllFile.Name}.bytes";
                    var pdbFileName = $"{pdbFile.Name}.bytes";
                    var dllTargetPath = Path.Combine(dlcDir, dllFileName);
                    var pdbTargetPath = Path.Combine(dlcDir, pdbFileName);
                    //拷回到DLC根目录下
                    File.Copy(dllFile.FullName, dllTargetPath, true);
                    File.Copy(pdbFile.FullName, pdbTargetPath, true);
                    AssetDatabase.Refresh();

                    var group = dlcInfo.Groups.FirstOrDefault(group => group.Name.Equals(dlcInfo.DLCName));
                    var dllobj = AssetDatabase.LoadAssetAtPath<TextAsset>(Path.Combine(dlcDir, dllFileName));
                    var pdbobj = AssetDatabase.LoadAssetAtPath<TextAsset>(Path.Combine(dlcDir, pdbFileName));
                    string dllGuid = GetGuidOfAsset(dllobj);
                    string pdbGuid = GetGuidOfAsset(pdbobj);
                    appendAsset(group, dllGuid, dllobj.name);
                    appendAsset(group, pdbGuid, pdbobj.name);

                    var dllReference = new AssetReferenceT<TextAsset>(dllGuid);
                    var pdbReference = new AssetReferenceT<TextAsset>(pdbGuid);

                    intro.dllReferences = new AssetReference[] { dllReference };
                    intro.pdbReferences = new AssetReference[] { pdbReference };

                    PrefabUtility.SaveAsPrefabAsset(introPrefab, introPath);
                    AssetDatabase.Refresh();
                }
            }

            void appendAsset(AddressableAssetGroup group, string assetGuid, string address)
            {
                var set = AddressableAssetSettingsDefaultObject.GetSettings(false);
                var entriesAdded = new List<AddressableAssetEntry>();
                var entry = set.CreateOrMoveEntry(assetGuid, group, false, false);
                entry.address = address;
                entriesAdded.Add(entry);
                set.SetDirty(AddressableAssetSettings.ModificationEvent.EntryMoved, entriesAdded, true, false);
            }

            static string GetGuidOfAsset(UnityEngine.Object asset)
            {
                return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetOrScenePath(asset));
            }


            void director(DirectoryInfo dir, string dstDllName, string dstPdbName, out FileInfo dllFile, out FileInfo pdbFile)
            {
                dllFile = null;
                pdbFile = null;
                foreach (FileInfo f in dir.GetFiles())
                {
                    if (f.Name.Equals(dstDllName, StringComparison.Ordinal))
                        dllFile = f;
                    if (f.Name.Equals(dstPdbName, StringComparison.Ordinal))
                        pdbFile = f;
                }
                if (dllFile != null && pdbFile != null)
                    return;
                foreach (DirectoryInfo d in dir.GetDirectories())
                    director(d, dstDllName, dstPdbName, out dllFile, out pdbFile);
            }
        }

        void CompileDlcWithCommandLine(string programDir, string dlcName)
        {
            BuildDll(programDir, dlcName);
        }
        private void BuildDll(string programDir, string dlcName)
        {
            // 1️⃣ 优先尝试 dotnet 编译
            string dotnetPath = "dotnet";

            // 2️⃣ 查找 csproj
            string csprojPath = Directory.GetFiles(programDir, "*.csproj", SearchOption.TopDirectoryOnly).FirstOrDefault();
            if (string.IsNullOrEmpty(csprojPath))
            {
                LogError($"❌ 未找到 {dlcName} 的 csproj 文件，无法编译。");
                return;
            }

            // 3️⃣ 命令行参数：构建为 Release 模式
            string args = $"build \"{csprojPath}\" -c Release";

            // 4️⃣ 启动命令行
            var process = new Process();
            process.StartInfo.FileName = dotnetPath;
            process.StartInfo.Arguments = args;
            process.StartInfo.WorkingDirectory = programDir;
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.StartInfo.CreateNoWindow = true;

            Log($"⚙️ 正在编译 {dlcName}.dll via dotnet build...");

            process.Start();
            string stdout = process.StandardOutput.ReadToEnd();
            string stderr = process.StandardError.ReadToEnd();
            process.WaitForExit();

            if (process.ExitCode == 0)
            {
                Log($"✅ {dlcName}.dll 编译成功！\n{stdout}");
            }
            else
            {
                LogError($"❌ {dlcName}.dll 编译失败！\n{stderr}");
            }
        }
    }
}
#endif